package de.tudarmstadt.fgbs.cafe.structure;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Class, which represents a train run (ger.: Zuglauf)
 * 
 * @author Chris
 * @version 0.1
 * 
 */

public class Zuglauf implements Comparable<Zuglauf>, Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -4476715554357600828L;

    private String number;
    private boolean isWende;
    private boolean isReady;
    private boolean personenZug;
    private int umlauf;
    private int baureihe;
    private String gattung;
    private short plus;
    private int vmax;
    private Zuglauf kommtAus;
    private Zuglauf wirdZu;
    private String kommtAusNr = "";
    private String wirdZuNr = "";
    private List<Wegpunkt> stationen;
    private Map<String, Integer> vmaxTable;
    public boolean isRegio = false;
    public boolean isFern = false;
    public boolean isCargo = false;

    public Zuglauf() {
	vmaxTable = new HashMap<String, Integer>();
	vmaxTable.put("ICE", 160);
	vmaxTable.put("TGV", 160);
	vmaxTable.put("EC", 140);
	vmaxTable.put("IC", 140);
	vmaxTable.put("RE", 120);
	vmaxTable.put("RB", 120);
	vmaxTable.put("FR", 100);
	vmaxTable.put("TX", 100);
	vmaxTable.put("FE", 100);
	vmaxTable.put("S", 120);
    }

    public void export() {

    }

    public boolean passesStation(List<Bahnhof> stationList) {
	for (Iterator<Wegpunkt> it = stationen.iterator(); it.hasNext();) {
	    Wegpunkt currentWP = it.next();
	    for (Iterator<Bahnhof> it1 = stationList.iterator(); it1.hasNext();) {
		Bahnhof currentBf = it1.next();
		if (currentBf.getKurzbez().equals(
			currentWP.getBahnhof().getKurzbez()))
		    return true;
	    }
	}
	return false;
    }

    public Wegpunkt getStart() {
	return stationen.get(0);
    }

    public Wegpunkt getDestination() {
	return stationen.get(stationen.size() - 1);
    }

    /**
     * @return the number
     */
    public String getNumber() {
	return number;
    }

    public String getNumberFPLPrint() {
	return gattung + number;
    }

    public String getNumberDisplay() {
	return number + " (" + gattung + ")";
    }

    public static String getNumberFromDisplay(String displayZN) {
	if (displayZN != null) {
	    String[] displayParts = displayZN.split(" ");
	    if (displayParts.length > 0) {
		return displayParts[0];
	    }
	}
	return null;
    }

    /**
     * @param number
     *            the number to set
     */
    public void setNumber(String number) {
	this.number = number;
	this.gattung = number.replaceAll("[0-9]", "");
	if (this.gattung.equals("ICE") || this.gattung.equals("IC")
		|| this.gattung.equals("EC") || this.gattung.equals("TGV"))
	    this.isFern = true;
	else if (this.gattung.equals("RE") || this.gattung.equals("RB")
		|| this.gattung.equals("S"))
	    this.isRegio = true;
	else
	    this.isCargo = true;
    }

    /**
     * @return the isWende
     */
    public boolean isWende() {
	return isWende;
    }

    /**
     * @param isWende
     *            the isWende to set
     */
    public void setWende(boolean isWende) {
	this.isWende = isWende;
    }

    /**
     * @return the isReady
     */
    public boolean isReady() {
	return isReady;
    }

    /**
     * @param isReady
     *            the isReady to set
     */
    public void setReady(boolean isReady) {
	this.isReady = isReady;
    }

    /**
     * @return the personenZug
     */
    public boolean isPersonenZug() {
	return personenZug;
    }

    /**
     * @param personenZug
     *            the personenZug to set
     */
    public void setPersonenZug(boolean personenZug) {
	this.personenZug = personenZug;
    }

    /**
     * @return the umlauf
     */
    public int getUmlauf() {
	return umlauf;
    }

    /**
     * @param umlauf
     *            the umlauf to set
     */
    public void setUmlauf(int umlauf) {
	this.umlauf = umlauf;
    }

    /**
     * @return the gattung
     */
    public String getGattung() {
	return gattung;
    }

    /**
     * @param baureihe
     *            the gattung to set
     */
    public void setGattung(String gattung) {
	this.gattung = gattung;
	determineVmax();
	determineZugTyp();
    }

    /**
     * @return the baureihe
     */
    public int getBaureihe() {
	return baureihe;
    }

    /**
     * @param baureihe
     *            the baureihe to set
     */
    public void setBaureihe(int baureihe) {
	this.baureihe = baureihe;
    }

    /**
     * @return the plus
     */
    public short getPlus() {
	return plus;
    }

    /**
     * @param plus
     *            the plus to set
     */
    public void setPlus(short plus) {
	this.plus = plus;
    }

    /**
     * @return the vmax
     */
    public int getVmax() {
	return vmax;
    }

    /**
     * @param vmax
     *            the vmax to set
     */
    public void setVmax(int vmax) {
	this.vmax = vmax;
    }

    /**
     * @return the kommtAus
     */
    public Zuglauf getKommtAus() {
	return kommtAus;
    }

    /**
     * @param kommtAus
     *            the kommtAus to set
     */
    public void setKommtAus(Zuglauf kommtAus) {
	this.kommtAus = kommtAus;
    }

    /**
     * @return the wirdZu
     */
    public Zuglauf getWirdZu() {
	return wirdZu;
    }

    /**
     * @param wirdZu
     *            the wirdZu to set
     */
    public void setWirdZu(Zuglauf wirdZu) {
	this.wirdZu = wirdZu;
    }

    /**
     * @return the stationen
     */
    public List<Wegpunkt> getStationen() {
	return stationen;
    }

    /**
     * @param stationen
     *            the stationen to set
     */
    public void setStationen(List<Wegpunkt> stationen) {
	this.stationen = new ArrayList<Wegpunkt>();
	this.stationen.addAll(stationen);
    }

    /**
     * @return the kommtAusNr
     */
    public String getKommtAusNr() {
	return kommtAusNr;
    }

    /**
     * @param kommtAusNr
     *            the kommtAusNr to set
     */
    public void setKommtAusNr(String kommtAusNr) {
	this.kommtAusNr = kommtAusNr;
    }

    /**
     * @return the wirdZuNr
     */
    public String getWirdZuNr() {
	return wirdZuNr;
    }

    /**
     * @param wirdZuNr
     *            the wirdZuNr to set
     */
    public void setWirdZuNr(String wirdZuNr) {
	this.wirdZuNr = wirdZuNr;
    }

    @Override
    public int compareTo(Zuglauf o) {
	return this.getNumber().compareTo(o.getNumber());
    }

    public Wegpunkt getWegpunkt(Bahnhof bhf) {
	for (Iterator<Wegpunkt> it = stationen.iterator(); it.hasNext();) {
	    Wegpunkt current = it.next();
	    if (current.getBahnhof().getKurzbez().equals(bhf.getKurzbez()))
		return current;
	}
	return null;
    }

    public boolean incrementAbfahrtOnly(Bahnhof bhf, int minutes) {
	Wegpunkt succ = null;
	Wegpunkt curr = null;
	for (Iterator<Wegpunkt> it = stationen.iterator(); it.hasNext();) {
	    Wegpunkt temp = it.next();
	    if (temp.getBahnhof().getKurzbez().equals(bhf.getKurzbez())) {
		curr = temp;
	    } else if (curr != null) {
		succ = temp;
		break;
	    }
	}
	if (curr != null) {
	    String newAbfahrt = curr.changeStringTime(curr.getAbfahrt(),
		    minutes);
	    String ankunft = curr.getAnkunft();
	    if (curr.compareStringTime(ankunft, newAbfahrt) > 0)
		return false;
	    else {
		if (succ != null) {
		    String succAn = succ.getAnkunft();
		    if (!(curr.compareStringTime(newAbfahrt, succAn) > 0)) {
			curr.modifyAbfahrt(minutes);
			return true;
		    }
		} else {
		    curr.modifyAbfahrt(minutes);
		    return true;
		}
	    }
	}
	return false;
    }

    public boolean incrementAnkunftOnly(Bahnhof bhf, int minutes) {
	Wegpunkt pre = null;
	Wegpunkt curr = null;
	for (Iterator<Wegpunkt> it = stationen.iterator(); it.hasNext();) {
	    Wegpunkt temp = it.next();
	    if (temp.getBahnhof().getKurzbez().equals(bhf.getKurzbez())) {
		curr = temp;
	    } else if (curr == null) {
		pre = temp;
	    } else {
		break;
	    }
	}
	if (curr != null) {
	    String newAnkunft = curr.changeStringTime(curr.getAnkunft(),
		    minutes);
	    String abfahrt = curr.getAbfahrt();
	    if (curr.compareStringTime(newAnkunft, abfahrt) > 0)
		return false;
	    else {
		if (pre != null) {
		    String preAb = pre.getAbfahrt();
		    if (!(curr.compareStringTime(preAb, newAnkunft) > 0)) {
			curr.modifyAnkunft(minutes);
			return true;
		    }
		} else {
		    curr.modifyAnkunft(minutes);
		    return true;
		}
	    }
	}
	return false;
    }

    public void incrementScheduleTime(Bahnhof start, Bahnhof end, int minutes) {
	if (this.getWegpunkt(start).timeModificationPossible(minutes, true)
		&& this.getWegpunkt(end).timeModificationPossible(minutes,
			false)) {
	    this.getWegpunkt(start).modifyAbfahrt(minutes);
	    this.getWegpunkt(end).modifyAnkunft(minutes);
	}
    }

    private void determineVmax() {
	Integer vmax = vmaxTable.get(this.gattung);
	if (vmax == null)
	    vmax = 120;
	this.vmax = vmax;
    }

    private void determineZugTyp() {
	this.isCargo = false;
	this.isFern = false;
	this.isRegio = false;

	if (this.gattung.equals("ICE") || this.gattung.equals("IC")
		|| this.gattung.equals("TGV") || this.gattung.equals("EC"))
	    this.isFern = true;
	else if (this.gattung.equals("RE") || this.gattung.equals("RB")
		|| this.gattung.equals("S"))
	    this.isRegio = true;
	else
	    this.isCargo = true;
    }

    public void incrementWholeZuglauf(int minutes) {
	for (int i = 0; i < stationen.size(); i++) {
	    if (i > 0)
		stationen.get(i).modifyAnkunft(minutes);
	    if (i < stationen.size() - 1)
		stationen.get(i).modifyAbfahrt(minutes);
	}
    }
}
